package com.study.www.service.impl;

import com.study.www.config.QuartzJobFactory;
import com.study.www.enums.ConfigEnum;
import com.study.www.model.JobConfig;
import com.study.www.model.mapper.ConfigRepository;
import com.study.www.service.JobConfigService;
import org.apache.commons.lang3.StringUtils;
import org.quartz.*;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
public class JobConfigServiceImpl implements JobConfigService {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    @Autowired
    private ConfigRepository configRepository;


    /**
     *
     * 系统启动-启动所有的任务
     * @return: void
     */
    @PostConstruct
    public void startInitJobs() throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduler.clear();
        List<JobConfig> configList = configRepository.findAll();
        for (JobConfig config : configList) {
            if (ConfigEnum.STATUS_START.getCode().equals(config.getStatus())){
                try {
                    addOrUpdateJob(config);
                } catch (SchedulerException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public boolean isValidExpression(String cronExpression) {
        CronTriggerImpl trigger = new CronTriggerImpl();
        try {
            trigger.setCronExpression(cronExpression);
            Date date = trigger.computeFirstFireTime(null);
            return date != null;
        } catch (Exception e) {
        }
        return false;
    }

    @Override
    public void update(Long id, String status) throws Exception {
        //判断是否有此ID的数据
        JobConfig config = configRepository.getById(id);
        if (config==null){
            new RuntimeException("未找到此定时任务");
        }
        if ("1".equals(status)){
            if(config.getStatus()==status){
                return;
            }else{
                // stop 禁用
                config.setStatus(ConfigEnum.STATUS_STOP.getCode());
                deleteJob(config);
            }
        }else{
            if(config.getStatus()==status){
                return;
            }else{
                //start 启用
                config.setStatus(ConfigEnum.STATUS_START.getCode());
                addOrUpdateJob(config);
            }
        }
        int i = configRepository.setStatusById(config.getStatus(), config.getId());

    }

    @Override
    public void updateCron(Long id, String cronSchedule) throws SchedulerException {
        int i= configRepository.setScheduleById(cronSchedule,id);
        JobConfig config= configRepository.getById(id);
        addOrUpdateJob(config);
        if (i<=0){
            throw  new RuntimeException("500!");
        }
    }

    @Override
    public void nowRunJob(Long id) throws SchedulerException {
        Scheduler scheduler=schedulerFactoryBean.getScheduler();
        Optional<JobConfig> config = configRepository.findById(id);
        TriggerKey triggerKey = TriggerKey.triggerKey(config.get().getJobName(), config.get().getJobGroup());
        JobKey jobKey = this.getJobKey(config.get());
        JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(jobKey).build();
        jobDetail.getJobDataMap().put(QuartzJobFactory.SCHEDULEJOBKEY,config.get());
        if(!scheduler.checkExists(triggerKey)){
            Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
                    .startNow()
                    .build();
            scheduler.scheduleJob(jobDetail,trigger);
        }else{
            JobDataMap jobDataMap=new JobDataMap();
            jobDataMap.put(QuartzJobFactory.SCHEDULEJOBKEY,config.get());
            scheduler.triggerJob(jobKey,jobDataMap);
        }
    }

    /**
     * 增加任务OR更新任务
     * @param :com.study.www.model.config
     * @Date: 2018/2/26 9:57
     * @return: void
     */
    private void addOrUpdateJob(JobConfig config) throws SchedulerException {
        //得到调度器
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        JobKey jobKey = this.getJobKey(config);
        //获得触发器
        TriggerKey triggerKey = TriggerKey.triggerKey(config.getJobName(), config.getJobGroup());
        CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);

        //判断触发器是否存在（如果存在说明之前运行过但是在当前被禁用了，如果不存在说明一次都没运行过）
        if (trigger == null){
            //新建一个工作任务 指定任务类型为串接进行的
            JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(jobKey).build();
            //将工作添加到工作任务当中去
            jobDetail.getJobDataMap().put(QuartzJobFactory.SCHEDULEJOBKEY,config);
            TriggerBuilder<Trigger> triggerBuilder=TriggerBuilder.newTrigger().withIdentity(triggerKey);
//            if(new Date().compareTo(startTime)<=0){//开始时间如果已经过去quartz默认立即执行一次，所以需要判断下，不让立即执行
//                triggerBuilder.startAt(startTime);
//            }
            //创建触发器并将cron表达式对象给塞入
            trigger = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(config.getCron())).build();
            //在调度器中将触发器和任务进行组合
            scheduler.scheduleJob(jobDetail,trigger);
        }else if(StringUtils.isNotBlank(config.getStatus())&&ConfigEnum.STATUS_START.getCode().equals(config.getStatus())){
            //按照新的规则进行
            TriggerBuilder<CronTrigger> triggerBuilder = trigger.getTriggerBuilder().withIdentity(triggerKey);
//            if(new Date().compareTo(startTime)<=0){//开始时间如果已经过去quartz默认立即执行一次，所以需要判断下，不让立即执行
//                triggerBuilder.startAt(startTime);
//            }
            trigger=triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(config.getCron())).build();
            //刷新触发器
            scheduler.rescheduleJob(triggerKey,trigger);
        }else if(StringUtils.isBlank(config.getStatus())){
            throw new SchedulerException(config.getJobName()+"运行状态为空！");
        }
    }

    /**
     *删除任务
     *
     * @param : com.study.www.model.config
     * @Date: 2018/2/24 18:23
     * @return: void
     */
    private void deleteJob(JobConfig config) throws SchedulerException {
        //得到调度器
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        //找到key值
        JobKey jobKey = this.getJobKey(config);
        //从触发器找到此任务然后进行删除
//        scheduler.deleteJob(jobKey);
        scheduler.pauseJob(jobKey);//暂停任务

    }


    /**
     * 根据name和group得到任务的key
     *
     * @param :com.study.www.model.config
     * @Date: 2018/2/24 18:27
     * @return: org.quartz.JobKey
     */
    private JobKey getJobKey(JobConfig config){
        return getJobKey(config.getJobName(),config.getJobGroup());
    }

    private JobKey getJobKey(String name, String group) {
        return JobKey.jobKey(name,group);
    }

}
